package com.sakura.demo2.gateway.config;

import cn.hutool.core.util.ArrayUtil;
import com.sakura.demo2.gateway.authentication.GatewayJwtTokenAuthenticationManager;
import com.sakura.demo2.gateway.filter.GatewayCorsFilter;
import com.sakura.demo2.gateway.filter.IgnoreUrlsRemoveJwtFilter;
import com.sakura.demo2.gateway.filter.UserInfoFromJwtGlobalFilter;
import com.sakura.demo2.gateway.handler.RestAccessDeniedHandler;
import com.sakura.demo2.gateway.handler.RestAuthenticationEntryPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authorization.ReactiveAuthorizationManager;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.oauth2.server.resource.web.server.ServerBearerTokenAuthenticationConverter;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.authentication.AuthenticationWebFilter;
import org.springframework.security.web.server.authorization.AuthorizationContext;

/**
 * @Author: zhengcan
 * @Date: 2022/5/13
 * @Description: 网关安全配置
 * @Version: 1.0.0 创建
 */
@Configuration
@EnableWebFluxSecurity
public class GatewaySecurityConfig {

    @Autowired
    private RestAuthenticationEntryPoint restAuthenticationEntryPoint;
    @Autowired
    private RestAccessDeniedHandler restAccessDeniedHandler;
    /**
     * jwt的鉴权管理器
     */
    @Autowired
    private ReactiveAuthorizationManager<AuthorizationContext> accessManager;
    /**
     * jwt token验证管理器
     */
    @Autowired
    private GatewayJwtTokenAuthenticationManager gatewayJwtTokenAuthenticationManager;
    @Autowired
    private IgnoreUrlsRemoveJwtFilter ignoreUrlsRemoveJwtFilter;
    @Autowired
    private IgnoreUrlsConfig ignoreUrlsConfig;
    @Autowired
    private UserInfoFromJwtGlobalFilter userInfoFromJwtGlobalFilter;
    @Autowired
    private GatewayCorsFilter gatewayCorsFilter;


    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {

        // 由自定义的token认证管理器接管默认的JwtReactiveAuthenticationManager管理器
        AuthenticationWebFilter authenticationWebFilter = new AuthenticationWebFilter(gatewayJwtTokenAuthenticationManager);
        authenticationWebFilter.setServerAuthenticationConverter(new ServerBearerTokenAuthenticationConverter());

        http.authorizeExchange()
                // 白名单直接放行
                .pathMatchers(ArrayUtil.toArray(ignoreUrlsConfig.getUrls(), String.class)).permitAll()
                // 其他的请求必须鉴权，使用鉴权管理器
                .anyExchange().access(accessManager)
                .and()
                .exceptionHandling()
                // 自定义授权异常处理器
                .accessDeniedHandler(restAccessDeniedHandler)
                // 自定义认证异常处理器
                .authenticationEntryPoint(restAuthenticationEntryPoint)
                .and()
                // 跨域过滤器
                .addFilterAt(gatewayCorsFilter, SecurityWebFiltersOrder.CORS)
                // 对白名单路径，在认证拦截器前直接移除JWT请求头
                .addFilterBefore(ignoreUrlsRemoveJwtFilter, SecurityWebFiltersOrder.AUTHENTICATION)
                // 设置自定义的token认证过滤器
                .addFilterAt(authenticationWebFilter, SecurityWebFiltersOrder.AUTHENTICATION)
                .addFilterAfter(userInfoFromJwtGlobalFilter, SecurityWebFiltersOrder.AUTHENTICATION)
                .csrf().disable()
                .httpBasic().disable()
                .cors();

        return http.build();
    }

}
